package com.simple.relaxed.agent;

import com.simple.relaxed.manager.impl.AgentManager;
import lombok.Setter;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 代理增强类，被此类代理的对象，其中的方法，使用@AgentMethod注解标记的方法将会被代理类强制扔到UI线程中执行
 */
public class AgentHandler implements InvocationHandler {

    /**
     * 被增强的类的对象
     */
    private Object object;

    /**
     * 上下文对象，必不可少，因为需要依赖此对象，获取全局唯一的UI线程
     */
    @Setter
    private Context context;

    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");

    public AgentHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        // 判断方法名，是否是需要增强的方法
        Map<Object, List<Method>> lookup = AgentManager.getInstance().lookup(object.getClass());
        TaskDispatcher uiTaskDispatcher = context.getUITaskDispatcher();
        Collection<List<Method>> values = lookup.values();
        AtomicReference<Object> obj = new AtomicReference<>();
        for (List<Method> methods : values) {
            if (contains(methods, method)) {
                uiTaskDispatcher.asyncDispatch(() -> {
                    HiLog.info(LABEL_LOG, "%s", "Run in ".concat(Thread.currentThread().getName()));
                    Object invoke = null;
                    try {
                        invoke = method.invoke(object, objects);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    obj.set(invoke);
                });
                break;
            } else {
                return method.invoke(object, objects);
            }
        }
        return obj.get();
    }

    /**
     * 调用此方法，判断指定的Method是否存在于指定的List容器中
     *
     * @param methods Method的List容器
     * @param method  模板Method对象
     * @return 匹配到时，则返回true， 匹配不到时，则返回false
     */
    private boolean contains(List<Method> methods, Method method) {
        for (Method m : methods) {
            if (m.getName().equals(method.getName())) {
                return true;
            }
        }
        return false;
    }
}
